package com.study.zkyxgs1.service.impl;

import com.study.zkyxgs1.exception.ZkyxgsException;
import com.study.zkyxgs1.model.User;
import com.study.zkyxgs1.service.UserService;
import com.study.zkyxgs1.utils.DBUtils;
import com.study.zkyxgs1.utils.ExceptionConstant;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * 人员管理业务实现类
 * @author weixiaochun
 * @date 2022/6/14 20:36
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    /**
     * 可根据注入的名称切换es或mongo
     * es: esDB
     * mongo: mongoDB
     */
    @Autowired
    @Qualifier("mongoDB")
    private DBUtils<User> dbUtils;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 插入单挑数据
     * 使用失效模式，保证缓存一致性
     * @param user 人员信息
     * @return
     */
    @Override
    @CacheEvict(value = {"userCache"}, allEntries = true)
    public void insert(User user) {
        dbUtils.save(user);
    }

    /**
     * 更新数据（默认根据id进行更新）
     * 使用失效模式，保证缓存一致性
     * @param user 人员信息
     * @return
     */
    @Override
    @CacheEvict(value = {"userCache"}, allEntries = true)
    public boolean update(User user) {
        return dbUtils.updateById(user);
    }

    /**
     * 删除数据（默认根据id进行删除）
     * 使用失效模式，保证缓存一致性
     * @param id 人员id
     * @return
     */
    @Override
    @CacheEvict(value = {"userCache"}, allEntries = true)
    public boolean delete(String id) {
        dbUtils.removeById(id, User.class);
        return true;
    }

    /**
     * 根据Id查询人员信息
     *
     * @param id 人员id
     * @return
     */
    @Override
    public User selectById(String id) {
        return dbUtils.getById(id, User.class);
    }

    /**
     * 根据name查询人员信息
     *
     * @param name 姓名
     * @return
     */
    @Override
    public List<User> selectByName(String name) {
        return dbUtils.getByOneQuery("name", name, User.class);
    }

    /**
     * 根据age查询人员信息
     *
     * @param age 年龄
     * @return
     */
    @Override
    public List<User> selectByAge(Integer age) {
        return dbUtils.getByOneQuery("age", age, User.class);
    }

    /**
     * 根据age的范围查询人员信息
     *
     * @param startAge 开始年龄
     * @param endAge   结束年龄
     * @return
     */
    @Override
    public List<User> selectByAgeRange(Integer startAge, Integer endAge) {
        return dbUtils.getByRange("age", startAge, endAge, User.class);
    }

    /**
     * 根据hobby查询人员信息
     *
     * @param hobbes 爱好
     * @return
     */
    @Override
    public List<User> selectByHobby(List<String> hobbes) {
        return dbUtils.getByList("hobby", hobbes, User.class);
    }

    /**
     * 查询所有人员信息
     *
     * @return
     */
    @Override
    @Cacheable(value = {"userCache"}, key = "#root.method.name")
    public List<User> selectAll() {
        RLock lock = redissonClient.getLock("selectALl-lock");;
        List<User> list;
        try{
            // 加分布式锁
            lock.lock();
            list = dbUtils.getAll(User.class);
        }catch (Exception e){
            e.printStackTrace();
            log.error("lock operation error");
            throw new ZkyxgsException(ExceptionConstant.LOCK_OPERATION_EXCEPTION.getCode(), ExceptionConstant.LOCK_OPERATION_EXCEPTION.getMessage());
        }finally {
            // 解锁
            lock.unlock();
        }
        return list;
    }

    /**
     * 嵌套查询description内部字段
     *
     * @param keys
     * @param val
     * @return
     */
    @Override
    public List<User> selectByDescription(List<String> keys, Object val) {
        keys.add(0, "description");
        return dbUtils.getByNest(keys, val, User.class);
    }

    /**
     * 嵌套查询
     *
     * @param map 嵌套结构数据
     * @return
     */
    @Override
    public List<User> selectByMap(Map<String, Object> map) {
        return dbUtils.getByNest(map, User.class);
    }
}
